package net.zoneland.knowledge.service.impl;

import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.google.common.collect.Streams;
import net.zoneland.knowledge.enums.CmpDnEnum;
import net.zoneland.knowledge.enums.MeetingSignInEnum;
import net.zoneland.knowledge.model.*;
import net.zoneland.knowledge.service.PartyService;
import net.zoneland.knowledge.utils.ExcelUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import net.zoneland.knowledge.dao.MeetingQrMapper;
import net.zoneland.knowledge.dao.MeetingSignInMapper;
import net.zoneland.knowledge.service.MeetingSignInService;
import net.zoneland.knowledge.utils.LoggerHelper;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

/**
 * 会议签到业务接口实现.
 * @author chw.
 * @version V1.0
 * 2022-11-18
 */
@Service
public class MeetingSignInServiceImpl implements MeetingSignInService {

    /**
     * LOG.
     */
    private static final Logger LOG = LoggerFactory.getLogger(MeetingSignInServiceImpl.class);

    /**
     * 会议(二维码)数据接口.
     */
    @Autowired
    private MeetingQrMapper meetingQrMapper;

    /**
     * 会议签到数据接口.
     */
    @Autowired
    private MeetingSignInMapper meetingSignInMapper;

    /**
     * 党组织信息接口.
     */
    @Autowired
    private PartyService partyService;

    /**
     * 导入行不符合要求.
     */
    private static final String IMPORT_LINE_NOT_FIT = "第%d行数据不符合要求：%s";

    /**
     * 根据用户id和会议id查询该用户签到情况.
     * @param meetingId 会议id
     * @param signInUserId 用户id
     * @return 签到情况
     */
    @Override
    public MeetingSignIn queryIndividualSignIn(final String meetingId, final String signInUserId) {
        return meetingSignInMapper.queryIndividualSignIn(meetingId, signInUserId);
    }

    /**
     * 保存用户会议签到信息.
     * @param meetingSignIn 会议签到信息.
     * @return 操作结果
     */
    @Override
    public int insert(final MeetingSignIn meetingSignIn) {
        return meetingSignInMapper.insert(meetingSignIn);
    }

    @Override
    public List<MeetingQr> findNotFinishMeetingDateByUserId(final String userID) {

        return Optional.ofNullable(userID)
                .map(meetingQrMapper::findNotFinishMeetingByUserId)
                .orElseGet(Collections::emptyList);
    }

    /**
     * 根据oaId查询我参加的会议
     * @param meetingSignIn 会议签到实体类.
     * @return 会议签到集合
     */
    @Override
    public List<MeetingQr> queryJoinMeetingByOaId(final MeetingSignIn meetingSignIn) {
        //一个用户会有多个参加的会议
        final List<MeetingSignIn> meetingIdList = meetingSignInMapper.selectDataBySignInUserId(meetingSignIn.getSignInUserId());
        return meetingIdList.stream()
                .map(MeetingSignIn::getMeetingId)
                .flatMap(meetingIdResult -> meetingQrMapper.queryIdByMeetingId(meetingIdResult).stream())
                .collect(Collectors.toList());
    }

    /**
     * 保存excel数据
     *
     * @param map 会议签到实体类
     * @return
     */
    @Override
    public void save(final Map<String, String> map, final String meetingId) {
        final String mobile = map.get(MeetingSignInEnum.MEETING_MOBILE.getField());
        final PartyUser partyUser = partyService.findPartyUserByMobile(mobile);
        // 判断是否已有当前参会人员
        final List<MeetingSignIn> meetingSignIns = meetingSignInMapper.querySignInUserByMeetingId(meetingId);

        if (CollectionUtils.isNotEmpty(meetingSignIns)) {
            final List<MeetingSignIn> meetingSignInList = meetingSignIns.stream()
                    .filter(item -> StringUtils.equals(item.getSignInUserId(), partyUser.getOaId()))
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(meetingSignInList)) {
                return;
            }
        }

        final MeetingSignIn meetingSignIn = new MeetingSignIn();
        meetingSignIn.setId(UUID.randomUUID().toString());
        meetingSignIn.setCrateTime(LocalDateTime.now());//创建时间
        meetingSignIn.setJob(map.get(MeetingSignInEnum.MEETING_JOB.getField()));//职务
        meetingSignIn.setMobile(mobile);//手机号
        meetingSignIn.setEmpNo(map.get(MeetingSignInEnum.MEETING_EMP_NO.getField()));//员工编号
        meetingSignIn.setSignInUserId(partyUser.getOaId());//oaid
        meetingSignIn.setCompanyName(CmpDnEnum.getNameByValue(partyUser.getCompanyDn()));//公司名称
        meetingSignIn.setCompanyDn(partyUser.getCompanyDn());//公司Dn
        meetingSignIn.setMeetingId(meetingId);
        meetingSignIn.setSignInUserName(map.get(MeetingSignInEnum.MEETING_SIGN_IN_USER_NAME.getField()));//员工名称
        meetingSignIn.setDeptName(map.get(MeetingSignInEnum.MEETING_DEPT_NAME.getField()));//部门名称

        final MeetingQr paramByMeetingId = meetingQrMapper.getParamByMeetingId(meetingId);
        //每个元素中的meetingTitle都是一样的
        meetingSignIn.setMeetingTitle(paramByMeetingId.getMeetingTitle());
        meetingSignInMapper.save(meetingSignIn);
    }

    @Override
    public String checkAndFillData(final List<Map<String, String>> excelDatas) {
        if (CollectionUtils.isEmpty(excelDatas)) {
            return "导入数据不能为空";
        }
        return Streams.mapWithIndex(
                        excelDatas.stream(),
                        this::checkRowDataAndCompeteInfo
                )
                .filter(Objects::nonNull)
                .collect(Collectors.joining());
    }

    /**
     * 根据会议id查询参会人员详情
     * @param meetingId 会议id
     * @return
     */
    @Override
    public List<MeetingSignIn> querySignInUserByMeetingId(final String meetingId) {
        final List<MeetingSignIn> result = meetingSignInMapper.querySignInUserByMeetingId(meetingId);
        return result;
    }

    /**
     * 批量删除签到人员
     * @param ids 签到人员id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchDeleteById(final String ids, final String meetingId) {
        final List<String> delList = Arrays.asList(ids.split(","));

        final int delNum = meetingSignInMapper.batchDeleteById(delList);
        // 更新参会人数
        meetingQrMapper.updateMeetingImportCount(meetingId);
        // 更新会议签到人数
        meetingQrMapper.updateMeetingSignCount(meetingId);
        return delNum;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult meetingUpload(final MultipartFile file, final String meetingId) throws IOException {

        //获取文件内容
        final List<Map<String, String>> excelData = ExcelUtils.meetingExcel(file.getInputStream());
        if (CollectionUtils.isEmpty(excelData)) {
            return new ResponseResult("文件数据为空", null);
        }

        //数据校验
        final String validInfo = checkAndFillData(excelData);
        if(StringUtils.isNotBlank(validInfo)) {
            return new ResponseResult(validInfo, null);
        }

        excelData.forEach(map -> save(map, meetingId));
        // 更新参会人员数量
        meetingQrMapper.updateMeetingImportCount(meetingId);

        // 更新签到人员数量
        meetingQrMapper.updateMeetingSignCount(meetingId);

        return new ResponseResult("上传成功", null);
    }

    /**
     * 数据校验.
     * @param map
     * @param index
     * @return
     */
    private String checkRowDataAndCompeteInfo(final Map<String, String> map, final long index) {
        final String empNo = map.get(MeetingSignInEnum.MEETING_EMP_NO.getField());
        final String mobile = map.get(MeetingSignInEnum.MEETING_MOBILE.getField());
        final PartyUser partyUser = partyService.queryPartyUserByEmpNoOrMobile(empNo, mobile);
        if (partyUser == null) {
            LOG.error("partyUser not found empNo:[{}], mobile:[{}]", empNo, mobile);
            return String.format(IMPORT_LINE_NOT_FIT, index + 2, "根据员工编号未找到党员信息");
        }
        return null;
    }

    /**
     * 用户会议签到.
     * @param id 会议id
     * @param user 登录用户
     * @return 签到信息
     */
    @Override
    public ResponseResult doSignIn(final String id, final LoginUserPojo user) {

        final ResponseResult rs = new ResponseResult();
        final MeetingQr meeting = meetingQrMapper.search(id);
        if (Objects.isNull(meeting)) {
            if (LOG.isErrorEnabled()) {
                LOG.error("会议不存在！ 会议id = {}", LoggerHelper.replaceBreakCharacters(id));
            }
            rs.setResult(ResponseResult.FAILED_RESULT);
            rs.setMessage("会议不存在！");
            return rs;
        }
        final LocalDateTime signInDate = LocalDateTime.now();

        //  判断会议结束时间，过时不能签到
        if (null != meeting.getMeetingEndDate() && meeting.getMeetingEndDate().isBefore(signInDate)) {
            rs.setResult(ResponseResult.FAILED_RESULT);
            rs.setMessage("会议已过结束时间不能签到！");
            return rs;
        }

        /*
         * 2022-12-08: 新增增加导入参会人员功能， 这边逻辑变化，原来是两种情况：
         *  queryIndividualSignIn查询有结果，说明已经签到了，否则没签到保存签到记录
         *  修改后：queryIndividualSignIn查询有结果要判断是否有签到时间，来判断是否签到
         *        如果没有数据则是导入人员外的人在签到。
         */
        final MeetingSignIn signIn = Optional.ofNullable(queryIndividualSignIn(id, user.getUserID()))
                .map(meetingSignIn -> {
                    //导入人员未签到
                    if (null == meetingSignIn.getSignInDate()) {
                        meetingSignIn.setSignInDate(signInDate);
                        meetingSignInMapper.updateSignInDate(meeting.getId(), user.getUserID(), signInDate);
                    }
                    return meetingSignIn;
                })
                .orElseGet(() -> saveMeetSignIn(meeting, user, signInDate)); //非导入人员签到

        rs.setData(signIn);

        //签到后要更新会议签到人数
        meetingQrMapper.updateMeetingSignCount(id);
        return rs;
    }

    /**
     * 会议签到.
     * @param meeting 会议信息
     * @param user 登录用户
     * @param signInDate 签到时间
     * @return 返回签到数据
     */
    private MeetingSignIn saveMeetSignIn(final MeetingQr meeting, final LoginUserPojo user, final LocalDateTime signInDate) {
        final MeetingSignIn signIn = new MeetingSignIn();
        signIn.setMeetingId(meeting.getId());
        signIn.setMeetingTitle(meeting.getMeetingTitle());
        signIn.setId(UUID.randomUUID().toString());
        signIn.setSignInUserId(user.getUserID());
        signIn.setSignInUserName(user.getUserName());
        signIn.setSignInDate(signInDate);
        signIn.setCrateTime(signInDate);
        meetingSignInMapper.insert(signIn);
        LOG.info("会议签到成功！ 会议id = {} 用户id = {} 签到时间 = {}", meeting.getId(), user.getUserID(), signInDate);
        // 参会人员加入成功后，更新会议表的参会人员数量
        meetingQrMapper.updateMeetingImportCount(meeting.getId());
        return signIn;
    }
}
